<?php
/**
 * @作者	海鹏
 * @package deep_captcha 验证码类
 * @version 1.0.0
 * 可以自由设置： 随机码，扭曲，干扰线，模糊 效果组合
 */
/*
if(!isset($_SESSION)){
   session_start();
}
$captcha = new Captcha();
$captcha->width  = 120;	//图片宽
$captcha->height = 50;	//图片高
//$captcha->isDebug=true;
$captcha->randomLength=4;
$captcha->createImage();
$_SESSION['platform']['captcha_code'] = $captcha->code;

*/
namespace library\deep;

class Captcha {

    //public $session_var = 'deep_captcha';		// Session名
    public $code  = '';	// 随机码
    public $width  = 250;	//图片宽
    public $height = 80;	//图片高

    public $isBlur = false;	//模糊
    public $isDebug = false;	//调试
	public $isSinLine=true;	//干扰线
	public $isWave=true;	//扭曲
	public $randomLength=null;
	
    public $backgroundColor = array(255, 255, 255);	//背景色
	// 前景色
    public $colors = array(
        array(27,78,181), // blue
        array(22,163,35), // green
        array(214,36,7),  // red
    );

    public $shadowColor = null; //阴影颜色 array(0, 0, 0);	

    /**
     * 字体效果 configuration
     * - font: TTF file							 * - spacing: 字符间距	像素pixel 
     * - minSize: 字体大小 最小值		     * - maxSize: 字体大小 最大值
     */
    public $fonts = array(
		array('spacing' => -1, 'minSize' => 30, 'maxSize' => 38, 'font' => 'tgl_0_17.ttf'),
		array('spacing' => -1, 'minSize' => 25, 'maxSize' => 34, 'font' => 'duality.ttf'),
    );

    public $resourcesPath = __DIR__ . '/fonts';	//资源路径 内放置文件夹fonts, words
    public $minWordLength = 3;	//最少字数 非字典随机文本生成
    public $maxWordLength = 6;	//最大字数 非字典随机文本生成 用于字典的话，表明字长

    /** 扭曲配置	 轴(axes) */
    private $period    = 12;	//y周期
    private $amplitude = 8;	 //y幅度

    private $maxRotation = 20;	 //  倾斜正负角度
    private $imageFormat = 'jpeg';	 //图片格式  jpeg or png
    private $im;	 //GD image
    private $scale = 2;	//内部图片大小系数

    public function __construct() { }

	// 建立图片
    public function createImage() {
        $_time_ms = microtime(true);

        /** Initialization */
        $this->imageAllocate();
        
        /** Text insertion */
        $this->code = $this->getCaptchaText();
        $fontcfg  = $this->fonts[array_rand($this->fonts)];
        $this->drawText($this->code , $fontcfg);

        //$_SESSION[$this->session_var] = $text;

		if($this->isWave){	// 扭曲
			$this->waveImage();
		}
        $this->reduceImage();	//重新取样

		if ($this->isSinLine) {
			$this->drawSinLine($this->getRandomColor());
			$this->drawSinLine($this->getRandomColor()); // $this->GdFgColor
		}

        if ($this->isBlur && function_exists('imagefilter')) {	//
            imagefilter($this->im, IMG_FILTER_GAUSSIAN_BLUR);	//高斯模糊
        }

        if ($this->isDebug) {
            imagestring($this->im, 1, 1, $this->height-8,
                $this->code ." {$fontcfg['font']} ".round((microtime(true)-$_time_ms)*1000)."ms",
                $this->GdFgColor );
        }

        $this->printImage();
        $this->destroyImage();
    }


    // 为图像分配颜色
    protected function imageAllocate() {
        if (!empty($this->im)) {
            imagedestroy($this->im);
        }
        $this->im = imagecreatetruecolor($this->width*$this->scale, $this->height*$this->scale);

        // 背景色
        $this->GdBgColor = imagecolorallocate($this->im,
            $this->backgroundColor[0],
            $this->backgroundColor[1],
            $this->backgroundColor[2]
        );
        imagefilledrectangle($this->im, 0, 0, $this->width*$this->scale, $this->height*$this->scale, $this->GdBgColor);	//画一矩形并填充

        // 前景色-文字和正弦干扰线
		$this->GdFgColor = $this->getRandomColor();

        // 阴影色
        if (!empty($this->shadowColor) && is_array($this->shadowColor) && count($this->shadowColor) >= 3) {
            $this->GdShadowColor = imagecolorallocate($this->im,
                $this->shadowColor[0],
                $this->shadowColor[1],
                $this->shadowColor[2]
            );
        }
    }

    /**
     * 生成随机颜色
     * @return 
     */
     protected function getRandomColor() {
		 $color           = $this->colors[mt_rand(0, sizeof($this->colors)-1)];
		 return imagecolorallocate($this->im, $color[0], $color[1], $color[2]);
	 }
	

    /**
     * 生成验证码文本
     * @return string Text
     */
     protected function getCaptchaText() {

			if(!$this->randomLength){
				$text = $this->getRandomCaptchaText();
			}else{
				$text = $this->getRandomCaptchaText($this->randomLength);
			}

        return $text;
    }


    /**
     * 生成随机文本
     * @return string Text
     */
    protected function getRandomCaptchaText($length = null) {
        if (empty($length)) {
            $length = mt_rand($this->minWordLength, $this->maxWordLength);
        }

        $words  = "abcdeghjmnpqstvwyABCDEFGKMNPQRSTUVWXY";
        $vocals = "23456789";

        $text  = '';
        $vocal = mt_rand(0, 1);
        for ($i=0; $i<$length; $i++) {
            if ($vocal) {
                $text .= substr($vocals, mt_rand(0, strlen($vocals)-1 ), 1);
            } else {
                $text .= substr($words, mt_rand(0, strlen($words)-1 ), 1);
            }
            $vocal = !$vocal;
        }
        return $text;
    }


    // 绘制文本
    protected function drawText($text, $fontcfg = array()) {
        if (empty($fontcfg)) {
            $fontcfg  = $this->fonts[array_rand($this->fonts)];// 选择字体
        }
        $fontfile = $this->resourcesPath.'/'.$fontcfg['font'];

        /** 最短的字体 9%*/
        $lettersMissing = $this->maxWordLength-strlen($text);
        $fontSizefactor = 1+($lettersMissing*0.09);

        // 绘图
        $x      = 20*$this->scale;
        $y      = round(($this->height*27/40)*$this->scale);
        $length = strlen($text);
        for ($i=0; $i<$length; $i++) {
            $degree   = mt_rand($this->maxRotation*-1, $this->maxRotation);
            $fontsize = mt_rand($fontcfg['minSize'], $fontcfg['maxSize'])*$this->scale*$fontSizefactor;
            $letter   = substr($text, $i, 1);

            if ($this->shadowColor) {//绘制阴影
                $coords = imagettftext($this->im, $fontsize, $degree,
                    $x+$this->scale+16, $y+$this->scale+16,
                    $this->GdShadowColor, $fontfile, $letter);
            }
            $coords = imagettftext($this->im, $fontsize, $degree,	$x+15, $y+15,
														$this->getRandomColor(), $fontfile, $letter);
            $x += ($coords[2]-$x) + ($fontcfg['spacing']*$this->scale);
        }
    }

     // 图像扭曲
    protected function waveImage() {
        // x轴扭曲
        $xp = $this->scale*$this->period*mt_rand(1,3);
        $phase = mt_rand(0, 90);	//相偏移

		for ($i = 0; $i < ($this->width*$this->scale); $i++) {
            imagecopy($this->im, $this->im,
                $i-1, sin($phase+$i/$xp) * ($this->scale*$this->amplitude),
                $i, 0, 
				1, $this->height*$this->scale);
        }

        // y轴扭曲
        $phase = mt_rand(0, 90);
        $yp = $this->scale*$this->period*mt_rand(1,2);
        for ($i = 0; $i < ($this->height*$this->scale); $i++) {
            imagecopy($this->im, $this->im,
                sin($phase+$i/$yp) * ($this->scale*$this->amplitude), $i-1,
                0, $i, 
				$this->width*$this->scale, 1);
        }
	}


     //重新取样
    protected function reduceImage() {
        $imResampled = imagecreatetruecolor($this->width, $this->height);
        imagecopyresampled($imResampled, $this->im, 0, 0, 0, 0,
            $this->width, $this->height,
            $this->width*$this->scale,		 $this->height*$this->scale
        );
        imagedestroy($this->im);
        $this->im = $imResampled;
    }


    // 生成图片
    protected function printImage() {
        if ($this->imageFormat == 'png' && function_exists('imagepng')) {
            header("Content-type: image/png");
            imagepng($this->im);
        } else {
            header("Content-type: image/jpeg");
            imagejpeg($this->im, null, 80);
        }
    }



    // 内存释放
    protected function destroyImage() {
        imagedestroy($this->im);
    }


	/*
	一般应用的正弦曲线公式为    y = A*  sin (  ω*t +或- θ )
	A 为波幅（纵轴）， ω 为（相位矢量）角速度， t 为时间（横轴）， θ 为相偏移（横轴左右）。
	*/
	//画正弦干扰线
	 private function drawSinLine($color)
	 {

		  $A=$this->height/mt_rand(4,7)  ;	//波幅（纵轴）
		  $axis_y=$this->height/2 + mt_rand(-5,5) ;	// 横轴 y坐标
		  $w=1/mt_rand(15,28);	//角速度
		  $phase=mt_rand(0,180);	//相偏移
		  $rnd=mt_rand(-1,1);	//随机 控制 线粗细

		  for($i=-$this->width/2;$i<$this->width/2;$i++)
		  {
			   $x=$i+$this->width/2;
			   $y=$A *  sin( $i * $w+$phase) +    $axis_y;
			   imagesetpixel($this->im,$x,$y,$color);
			   $rnd!=0?imagesetpixel($this->im,$x,$y+$rnd,$color):null;
		  }
	 }


}//-------class end-------------
